
import os
import Foundation

#if os(macOS)
import IOKit
#elseif os(iOS)
import UIKit
#endif


typealias Success = (_ result: String) -> Void
typealias Failure = (_ errMsg: String) -> Void

enum LOG_LEVEL: Int {
    case info = 0
    case debug
    case verbose
    case warning
    case error
    case fatal
}

enum LOG_APP: Int {
    case unknown = 0
    case OTigre
    case OLeao
    case OElefante
}

class PavaoManager: ObservableObject {

    // Remote Pavao service
    private var ipAddress: String?
    private var port: in_port_t?
    
    private var serialNumber: String = ""
    private var deviceType: Int = 0
    
    public static let instance = PavaoManager()
    
    @Published var serverState: Bool = false
    
    init(ipAddress: String? = nil, port: in_port_t? = nil) {
        self.ipAddress = ipAddress
        self.port = port
        
        self.serialNumber = getDeviceIdentifier()
        self.deviceType = determineOperatingSystem()
    }
    
    init() {
        
        self.serialNumber = getDeviceIdentifier()
        self.deviceType = determineOperatingSystem()
    }
    
    let logLevelString: [String] = ["unknown", "debug", "info", "warning", "error", "fatal"]
    func saveLog(logLevel: LOG_LEVEL, logContent: String, _ logApp: LOG_APP = .OLeao) {
        guard let ipAddress = self.ipAddress, let port = self.port else {
            print("IP address or port is not set.")
            return
        }
        
        let url: String = "http://\(ipAddress):\(port)/uploadLog"
        let jsonDict: [String: Any] = [
            "serial_number": self.serialNumber,
            "device_type": self.deviceType,
            "log_level": logLevel.rawValue,
            "log_content": logContent,
            "log_app": logApp.rawValue
        ]
        
        let jsonString = jsonDictToString(jsonDict: jsonDict)
        print("saveLog JSON String: \(jsonString)") // Debugging line
        DispatchQueue.global(qos: .background).async {
            self.postString(url: url, stringToPost: jsonString, timeout: 0.1) { result in
                print("saveLog Response: \(result)")
            } failure: { errMsg in
                print("saveLog errMsg: \(errMsg)")
            }
        }
        
      //  print("Response: \(responseString)")
    }
    
    
    func saveStat(uuid: String = "",
                  output: Int = 0) {
        guard let ipAddress = self.ipAddress, let port = self.port else {
            print("IP address or port is not set.")
            return
        }
        
        let url: String = "http://\(ipAddress):\(port)/uploadStat"
        let jsonDict: [String: Any] = [
            "serial_number": self.serialNumber,
            "device_type": self.deviceType,
            "uuid": uuid,
            "output": output
        ]
        
        let jsonString = jsonDictToString(jsonDict: jsonDict)
        print("saveStat JSON String: \(jsonString)") // Debugging line
        DispatchQueue.global(qos: .background).async {
            self.postString(url: url, stringToPost: jsonString, timeout: 0.1) { result in
                print("saveStat Response: \(result)")
            } failure: { errMsg in
                print("saveStat errMsg: \(errMsg)")
            }
        }

      //  print("Response: \(responseString)")
    }
    
    func saveResult(uuid: String = "",
                    url: String = "",
                    count: Int = -1,
                    model_name: String = "",
                    defect_name: String = "",
                    minX: Float = -1,
                    minY: Float = -1,
                    width: Float = -1,
                    height: Float = -1,
                    confidence: Float = -1,
                    area: Float = -1,
                    length_ratio: Float = -1,
                    grayscale_ratio: Float = -1) {
        guard let ipAddress = self.ipAddress, let port = self.port else {
            print("IP address or port is not set.")
            return
        }
        
        let urlDst: String = "http://\(ipAddress):\(port)/uploadData"
        let jsonDict: [String: Any] = [
            "serial_number": self.serialNumber,
            "device_type": self.deviceType,
            "url": url,
            "uuid": uuid,
            "count": count,
            "model_name": model_name,
            "defect_name": defect_name,
            "minX": minX,
            "minY": minY,
            "width": width,
            "height": height,
            "confidence": confidence,
            "area": area,
            "length_ratio": length_ratio,
            "grayscale_ratio": grayscale_ratio]
        
        let jsonString = jsonDictToString(jsonDict: jsonDict)
        print("saveResult JSON String: \(jsonString)") // Debugging line
        DispatchQueue.global(qos: .background).async {
            self.postString(url: urlDst, stringToPost: jsonString, timeout: 0.1) { result in
                print("saveResult Response: \(result)")
            } failure: { errMsg in
                print("saveResult errMsg: \(errMsg)")
            }
        }

      //  print("Response: \(responseString)")
        
    }
    
    internal func jsonDictToString(jsonDict: [String: Any]) -> String {
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: jsonDict, options: [])
            if let jsonString = String(data: jsonData, encoding: .utf8) {
                return jsonString
            }
        } catch {
            print("Error creating JSON string: \(error)")
        }
        return ""
    }
    
    private func postString(url: String, stringToPost: String, timeout: Double,  success: @escaping Success,  failure: @escaping Failure)  {
        guard let url = URL(string: url) else {
            print("Invalid URL")
            failure("Invalid URL")
            return
        }
        
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.httpBody = stringToPost.data(using: .utf8)
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.timeoutInterval = 60
        //var responseString = ""
        //let semaphore = DispatchSemaphore(value: 0)
        
        let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
            if let error = error {
                //print("Error: \(error.localizedDescription)")
                //semaphore.signal()
                failure("Error: \(error.localizedDescription)")
                return
            }
            
            if let httpResponse = response as? HTTPURLResponse {
                if httpResponse.statusCode == 200 {
                    let responseString = String(data: data ?? Data(), encoding: .utf8) ?? ""
                    success(responseString)
                } else {
                    //print("HTTP response status code: \(httpResponse.statusCode)")
                    failure("HTTP response status code: \(httpResponse.statusCode)")
                }
            }
            
            //semaphore.signal()
        }
        
        task.resume()
        //_ = semaphore.wait(timeout: DispatchTime.now() + timeout)
        
       // return responseString
    }
    private func getTime() -> String {
        return Date.now.ISO8601Format()
    }
    
    private func determineOperatingSystem() -> Int {
        #if os(iOS)
        return 1
        #elseif os(macOS)
        return 2
        #else
        return 0 // Optional: return 0 for other platforms
        #endif
    }
    
    private func getDeviceIdentifier() -> String {
        #if os(macOS)
        var serialNumber: String = "Unknown"
        let platformExpert = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice"))
        
        if platformExpert > 0 {
            if let serialNumberCF = IORegistryEntryCreateCFProperty(platformExpert, kIOPlatformSerialNumberKey as CFString, kCFAllocatorDefault, 0).takeUnretainedValue() as? String {
                serialNumber = serialNumberCF.trimmingCharacters(in: .whitespacesAndNewlines)
            }
            IOObjectRelease(platformExpert)
        }
        return serialNumber
        #elseif os(iOS)
        return UIDevice.current.identifierForVendor?.uuidString ?? ""
        
        #else
        return ""
        #endif
    }
    
    func testConnection(_ ipAddress: String?, _ port: String?, completion: @escaping (Bool) -> Void) {
        guard let ipAddress = ipAddress, let port = port else {
            print("IP address or port is not set.")
            completion(false)
            return
        }
        self.ipAddress = ipAddress
        self.port = in_port_t(port)
        var socketAddress = sockaddr_in()
        socketAddress.sin_family = sa_family_t(AF_INET)
        socketAddress.sin_port = in_port_t(port)?.bigEndian ?? 0
        inet_pton(AF_INET, ipAddress, &socketAddress.sin_addr.s_addr)
        
        let socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0)
        guard socketFileDescriptor != -1 else {
            print("Failed to create socket")
            completion(false)
            return
        }
        
        // 设置连接超时时间
        var timeoutVal = timeval(tv_sec: 5, tv_usec: 0)  // 设置秒和微秒
        let setsockoptResult = setsockopt(socketFileDescriptor, SOL_SOCKET, SO_RCVBUF, &timeoutVal, socklen_t(MemoryLayout<timeval>.size))
        
        if setsockoptResult != 0 {
            print("Failed to set socket timeout")
            close(socketFileDescriptor)
            completion(false)
            return
        }
        
        let convertedAddress = withUnsafePointer(to: &socketAddress) {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { $0 }
        }
        
        let connectResult = connect(socketFileDescriptor, convertedAddress, socklen_t(MemoryLayout<sockaddr_in>.size))
        close(socketFileDescriptor)
        
        if connectResult == 0 {
            print("Connection successful!")
            completion(true)
        } else {
            print("Failed to connect: \(errno)")
            completion(false)
        }
    }
}
